package com.apes.scm.income.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.income.model.MoneyIncome;
import com.apes.scm.income.model.MoneyIncomeItem;
import com.apes.scm.income.repository.MoneyIncomeRepository;
import com.apes.scm.masterdata.finance.model.AmtReceipt;
import com.apes.scm.masterdata.finance.model.BankAccount;
import com.apes.scm.masterdata.finance.model.PaymentMethodType;
import com.apes.scm.masterdata.finance.repository.AmtReceiptRepository;
import com.apes.scm.masterdata.finance.repository.BankAccountRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @BelongsProject: apes-server
 * @BelongsPackage: com.apes.fico.finance.service
 * @ClassName: MoneyIncomeService
 * @Author: pyb
 * @CreateTime: 2020-03-09 15:10
 * @Description: 资金收入服务
 * @Version: 1.0
 */
@Service("moneyIncomeService")
public class MoneyIncomeService extends DomainService {
    MoneyIncomeRepository moneyIncomeRepository;

    AmtReceiptRepository amtReceiptRepository;

    @Autowired
    private void setMoneyIncomeRepository(MoneyIncomeRepository moneyIncomeRepository, AmtReceiptRepository amtReceiptRepository) {
        this.moneyIncomeRepository = moneyIncomeRepository;
        this.amtReceiptRepository = amtReceiptRepository;
    }

    /**
     * 保存
     *
     * @param request
     * @return MoneyIncome
     */
    public MoneyIncome save(SimpleRequest request) {
        MoneyIncome income = createOrUpdateCustomerInfo(request);
        income.setPostDate(new Date());

        // 设置利润中心
        if(income.getDept().getProfitCenterId() == null) throw new RuntimeException("请联系行政中心配置部门的利润中心，门店编码：" + income.getDept().getId());
        income.setProfitCenterId(income.getDept().getProfitCenterId());
        return moneyIncomeRepository.saveAndFlush(income);
    }

    /**
     * app保存
     * @param request
     * @return
     */
    public MoneyIncome saveApp(SimpleRequest request){
        MoneyIncome moneyIncome = request.getO(MoneyIncome.class);
        Dept dept = moneyIncome.getDept();
        moneyIncome.setCompany(dept.getCompany());

        List<MoneyIncomeItem> incomeItems = moneyIncome.getMoneyIncomeItems();
        for (int i = 0; i < incomeItems.size(); i++) {
            incomeItems.get(i).setWeichatFlow(incomeItems.get(i).getBillNumber());
        }
        //checkPaymentType(incomeItems);
        String amtReceipt = request.getJO().getString("amtReceipt");
        AmtReceipt receipt = amtReceiptRepository.findOne(amtReceipt);
        if (ObjectUtils.isEmpty(receipt)){
            throw new RuntimeException("不存在的收入类型!");
        }
        String billNumber = request.getJO().getString("billNumber");

        // 设置利润中心
        if(moneyIncome.getDept().getProfitCenterId() == null){
            throw new RuntimeException("请联系行政中心配置部门的利润中心，门店编码：" + moneyIncome.getDept().getId());
        }
        moneyIncome.setProfitCenterId(moneyIncome.getDept().getProfitCenterId());

        // 明细处理
        MoneyIncomeItem moneyIncomeItem = moneyIncome.getMoneyIncomeItems().get(0);
        moneyIncomeItem.setAmtReceipt(receipt);
        moneyIncomeItem.setRemark(incomeItems.get(0).getNote());
        moneyIncomeItem.setIncomeAmount(incomeItems.get(0).getAmount());
        moneyIncomeItem.setReceivableAmount(incomeItems.get(0).getAmount());
        setPaymentMethodAccount(moneyIncomeItem);   // 添加收款账户

        return moneyIncomeRepository.saveAndFlush(moneyIncome);
    }

    /**
     * 添加收款账户
     * @param moneyIncomeItem MoneyIncomeItem
     */
    private void setPaymentMethodAccount(MoneyIncomeItem moneyIncomeItem) {
        if (!"03".equals(moneyIncomeItem.getPaymentMethodType().getId())) return;

        if (StringUtils.isEmpty(moneyIncomeItem.getAccountNumber()) && Objects.isNull(moneyIncomeItem.getBankAccount())) {
            throw new RuntimeException("转账的收款方式中，银行账号与银行账户字段同时为空，请检查");
        }

        // 如果银行账户与银行账号同时存在就 continue
        if (!StringUtils.isEmpty(moneyIncomeItem.getAccountNumber()) && Objects.nonNull(moneyIncomeItem.getBankAccount()) && !StringUtils.isEmpty(moneyIncomeItem.getBankAccount().getId()))
            return;

        /** 分别处理银行账号与账户 **/
        if (Objects.nonNull(moneyIncomeItem.getBankAccount()) && !StringUtils.isEmpty(moneyIncomeItem.getBankAccount().getId())) {
            // 根据银行账户获取银行账号
            moneyIncomeItem.setAccountNumber(moneyIncomeItem.getBankAccount().getAccountId());
        }

        if (!StringUtils.isEmpty(moneyIncomeItem.getAccountNumber())) {
            // 根据银行账号获取账户编码
            BankAccount bankAccount = SpringManager.getBean(BankAccountRepository.class)
                    .findAll(JpaDsl.toCriteriaByEq("accountId", moneyIncomeItem.getAccountNumber()))
                    .stream().findFirst()
                    .orElseThrow(() -> new RuntimeException("根据银行账号没有找到对应银行的账户信息"));
            moneyIncomeItem.setBankAccount(bankAccount);
        }
    }


    /**
     * 核查支付方式
     * @param incomeItems
     */
    private void checkPaymentType(List<MoneyIncomeItem> incomeItems) {
        //有效支付方式id
//        List<String> validPayId = Arrays.asList("01","02","03","08");
        for (int i = 0; i < incomeItems.size(); i++) {
            PaymentMethodType paymentMethodType = incomeItems.get(i).getPaymentMethodType();
//            if (!validPayId.contains(paymentMethodType.getId())){
//                throw new RuntimeException("该支付方式无效!");
//            }
            if ("对公转账".equals(paymentMethodType.getName())){
                JSONArray imgs = JSONArray.parseArray(incomeItems.get(i).getImgs());
                if (CollectionUtils.isEmpty(imgs)){
                    throw new RuntimeException("转账方式为对公转账时,转账凭证不得为空!");
                }
            }
        }
    }

    /**
     * 审核
     *
     * @param request
     * @return MoneyIncome
     */
    public MoneyIncome approve(SimpleRequest request) {
        MoneyIncome income = moneyIncomeRepository.findOne(request.getO(MoneyIncome.class).getId());
        income.setApproveDate(new Date());
        if (!ObjectUtils.isEmpty(getPerson(request))) {
            income.setApproveUID(getPerson(request));
        }
        income.setState("approve");

        pushOutboxMsg(income); //计算平台管理费

        MoneyIncome moneyIncome = moneyIncomeRepository.saveAndFlush(income);

        extracted(income);//生成待缴款单
        return moneyIncome;
    }

    private void extracted(MoneyIncome income) {
        //生成待缴款单
        List<Map> mapList = income.getMoneyIncomeItems().stream()
                .map(paymentMethod ->
                        MapUtil.mapper("amount", paymentMethod.getIncomeAmount(),
                                "paymentType", paymentMethod.getPaymentMethodType().getId(),
                                "paymentId", paymentMethod.getPaymentMethodType().getPaymentType().getId())
                ).collect(Collectors.toList());
        this.invoke("to.prepare.storeCashAndSave", JSON.toJSONString((MapUtil.mapper("orderId", income.getId(),
                "deptId", income.getDept().getId(), "sourceBusinessType", "MoneyIncome",
                "details", mapList))));
    }


    public void pushOutboxMsg(MoneyIncome moneyIncome) {
        // 推送计算平台服务费消息
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("fn.partnerCheck.calculateMoneyIncomeFee");
        wrapper.setAggregateId(moneyIncome.getId());
        wrapper.setPayload(JSON.toJSONString(MapUtil.mapper("id", moneyIncome.getId())));
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);

    }

    /**
     * 删除
     *
     * @param request
     * @return 删除成功
     */
    public String delete(SimpleRequest request) {
        MoneyIncome income = request.getO(MoneyIncome.class);
        moneyIncomeRepository.delete(income);
        return "删除成功";
    }

    /***
     * 保存会员和车辆数据
     */
    private MoneyIncome createOrUpdateCustomerInfo(SimpleRequest request) {
        JSONObject tempJson = request.getJO();
        MoneyIncome moneyIncome = request.getO(MoneyIncome.class);
        if (tempJson.get("appForm")!=null){
            moneyIncome.getMoneyIncomeItems().forEach(moneyIncomeItem -> {
                if (moneyIncomeItem.getPaymentMethodType().getId().equals("09"))
                    if (moneyIncomeItem.getCustomer() == null && moneyIncomeItem.getCustomerDept().getId() == null) {
                        throw new RuntimeException("收款方式为其他应收,必须传客户或者客户门店");
                    }
                if(moneyIncomeItem.getCustomerDept() != null) {
                    Optional.ofNullable(moneyIncomeItem.getCustomerDept().getCompany())
                            .orElseThrow(()-> new RuntimeException("没有找到对应的门店的公司信息，请检查！门店编码："+ moneyIncomeItem.getCustomerDept().getId()));
                    PartyRole customer = moneyIncomeItem.getCustomerDept().getCompany().getParty().getPartyRoleByType("Customer");
                    moneyIncomeItem.setCustomer(customer);
                }
            });
        }
        Object customerExpand = this.invoke("fn.customerExpand.updateOrInsert", MapUtil.mapper(
                "customerExpand", SpringManager.getBean(DomainService.class).invoke("fn.customerExpand.findOne", MapUtil.mapper(
                        "id",tempJson.get("customerExpand"))),
                "customer", tempJson.get("customer"),
                "customerCar", tempJson.get("customerCar")
        ));
        if (Objects.isNull(moneyIncome.getCompany())) {
            moneyIncome.setCompany(moneyIncome.getDept().getCompany());
        }
        moneyIncome.setCustomerExpand(ReflectUtil.getFieldValue(customerExpand,"id"));
        return moneyIncome;
    }

}
